#include <iostream>
#include <memory> // 智能指针头文件
#include "func.h"

using namespace std;

class A
{
	//public:
	//    A()
	//    {

	//    }

	//~A()
	//    {

	//    }
};

class B
{
public:
	B()
	{
		cout << "A()" << endl;
	}
	int getAdd()
	{
		return -1;
	}
	~B()
	{
		cout << "~A()" << endl;
	}
};

class C
{
public:
	C()
	{

	}
	int getAdd()
	{
		return -1;
	}
	~C()
	{

	}
public:
	int m_a;
};

shared_ptr<int> makes(int value)
{
	// return new int(value);// 不可以,无法把new得到的int*转换成shared_ptr.
	return shared_ptr<int>(new int(value));// 可以,显示的用int*创建的shared_ptr<int>
}

void myfunc(shared_ptr<int> ptemp)
{
	// 这里引用计数会加1,离开作用域后,就减1了.
	return;
}

void myfunc1(shared_ptr<int> &ptemp)
{
	// 这里引用计数不会加1
	return;
}

shared_ptr<int> myfunc2(shared_ptr<int> &ptemp)
{
	// 这里引用计数不会加1
	return ptemp;
}

void myDelete(int *p)// 我们的删除器,当整形指针用的,当引用计数为0,就会调用
{
	cout << "删除*p." << endl;
 delete p;
}

// 写个函数模板来封装shared_ptr数组
template<typename T>
shared_ptr<T> make_shared_array(size_t size)
{
	return shared_ptr<T>(new T[size], default_delete<T[]>());
}

auto myfuncC()
{
	return unique_ptr<string>(new string("i love you "));// 临时对象都是右值
}

unique_ptr<string> tuniqep()
{
	//unique_ptr<string> pr(new string("ss"));
	//return pr;// 从函数返回一个局部的unique_ptr对象,返回这种局部的对象,导致系统给我们成月光临时的unique_ptr对象,调用unique_ptr的移动构造函数
	return unique_ptr<string>(new string("aa"));
}

void mydeleteer(string *pdel)
{
	delete pdel;
	pdel = nullptr;
	// 日志
}
int main()
{
	system("chcp 65001");
	// mfc有内存泄漏的
#if 0
	// 1.new/delete
	// 1.1 new,delete是什么?
	// sizeof是关键字运算符,不是个函数
	// new,delete(关键字/运算符),不是个函数
	// malloc/free主要用于c语言编程中,new/delete用于c++编程中
	// new/delete,负责事情更多.具备对堆上所分配的内存进行初始化/释放(反初始化)的能力,这些能历史是malloc/free是所不具备的.
	// 构造函数和析构函数.
	// 1.2 operator new() 和operator delete()
	//
	int *pi = new int;
	delete pi;
	// operator new()和operator delete()是函数
	// new 干了两个事情,分配内存(通过operator new() 来分配内存),调用构造函数来初始化内存.
	// delete 也干了两个事情,先析构函数,后释放内存.

	// 1.3 new如何记录分配的内存大小供delete使用
	// 不同编译器new 内部有不同的实现方式.
	int *p = new int;// 4
	delete p;// 删除的时候,new内部有记录机制.

	// 1.数组
	int *p1 = new int[2];// int数组,两个元素,8字节

	A a;
	int ilen = sizeof(a);// 输出为1
	cout << "ilen : " << ilen << endl;// 类对象有地址,至少字节的地方.

	A *pA = new A();
	B b;// 纯静态函数不占用内存.

	ilen = sizeof(b);// 输出为1
	cout << "ilen : " << ilen << endl;// 类对象有地址,至少字节的地方.

	A *pA1 = new A[2]();// 6字节
	ilen = sizeof(A[2]);// 输出为2
	cout << "ilen : " << ilen << endl;// 类对象有地址,至少字节的地方.

	B *pB1 = new B[2]();// 这里泄漏6字节,而不是2字节,多出来的4字节是干嘛的
	// 疑问:为什么给类型A分配内存对象时多出来4字节,而给内置类型int动态分配内存对象数组时,并没有多出来4字节.
	int *p2 = new int[3];
	delete p2;// 没有用[] 直接释放p2页没有问题.
	delete[] p2;// 规范写法
	cout << "========" << endl;
	B *pB2 = new B[2]();
	delete pB2;// 系统报告异常了.
	//    A()
	//    A()
	//    ~A()
	// 这里其实是少析构了一次
	//delete[] pB2;// 这里为什么会知道是释放两次.

	// 1.5 new/delete / new[] 和delete[] 要配对使用.
	// 内置类型不需要析构函数,所以new[] 的时候,并没有析构函数.
	// 对于int类型,new[] ,delete p或者delete [] p ,效果一样.
	// 结论:如果一个对象,使用new[]来分配内存,却用单独的delete(而不是delete[])来使用内存,这个对象需要满足:
	// -->1.内置类型.
	// -->2.无自定义类型的析构函数类类型.没有析构函数,就可以使用delete p;

	//     B *pB2 = new B[2]();
	// delete pB2;// 系统报告异常了.
	// a.调用一次A的析构函数而不是两次,至少是表示有内存泄漏的
	// b.调用operator delte(pA),释放内存.造成异常.

	// A *pA = new A();
	// delete[] pA;// 要配对使用,否则程序错乱.
#endif

#if 0
	// 智能指针综述
	int *p = new int();
	int *q = p;
	int *r = q;// 只有pqr都不再使用,才能释放 掉这段内存.
	// new .delete的写法非常小心,防止早早的释放,也防止忘记释放,用好并不容易.
	// p裸指针,直接用new返回的指针,这种指针,强大,灵活,全程维护,一旦用错,后果很严重
	// 智能指针:就理解为裸指针进行包装,给裸指针外边包了一层,再也不用担心new出来的内存忘记释放了.
	// 建议使用智能指针,使用智能指针的程序更容易编写和调试.
	// c++有四种智能指针.
	// a.auto_ptr(98)已经被unique_ptr替代了.
	// b.unique_ptr
	// c.shared_ptr
	// d weak_ptr

	// 帮助我们进行动态分配对象,new出来的对象的生命周期的管理,能够有效防止内存泄漏.
	// 这三种智能指针都是类模板,我们将new获得地址赋给他们.
	// weak_ptr是辅助shared的
	// shared_ptr: 共享式指针,多个指针指向同一个对象,最后一个指针被销毁时,这个对象会被释放.
	// unique_ptr:独占式指针,同一个时间内,只有指针能够指向该对象.该对象的所有权可以移交出去的.
	// 你忘记delete的时候,智能指针能够帮助你delete,或者说,你压根不再需要自己delete,


	// shared_ptr基础
	// 共享所有权,不是被一个shared_ptr,而是被多个shared_ptr之间相互协作,有额外开销.
	// 工作机制: 引用计数,每个shared_ptr的拷贝都指向相同的内存,所以只有最后一个指向该内存的对象,shared_ptr指针不再需要指向该对象时.
	// shared_ptr被析构时,就会被释放
	// 这个shared_ptr指向其他的对象时,
	// 垃圾回收机制,从此不再担心对象何时被deleye

	// 类模板,用到<>:
	// 格式 shared_ptr<指向类型> 智能指针名
	std::shared_ptr<int> pi(new int(100));// 指针指向一个值为100的int型数据
	//shared_ptr<int> pp2 = new int(100);// err,不行,智能指针是explicit,不可以进行隐式类型转换,必须采用直接初始化形式
	shared_ptr<int> pi3 = makes(130);
	// 裸指针可以初始化shared_ptr,但不推荐,智能指针和裸指针不要穿插用/

	// 裸指针初始化shared_ptr:
	int *pi1 = new int(100);
	shared_ptr<int> pi2(pi1);// 不推荐

	// 默认空指针
	shared_ptr<int> pi4;// 指向为空
	// make_shared函数,标准库的函数模板,安全,高效,的分配和使用shared_ptr;
	// 它能够在动态内存,堆中分配初始化一个对象,然后返回指向此对象的shared_ptr

	shared_ptr<int> pi5 = make_shared<int>(100);
	shared_ptr<int> pi6 = make_shared<int>(100);
	// 这个ptr指向值为100的整形内存

	// 相当于5个字符a生成的字符串,这个指针指向了"aaaaa"的地址.
	shared_ptr<string> ps1 = make_shared<string>(5, 'a');
	// 类似于string mystr(5,'5');

	shared_ptr<int> pi7 = make_shared<int>();
	// pi7指向一个int 0,值为0;
	pi7 = make_shared<int>(400);
	// pi7指向新int,首先释放刚才指向的值.

	// 自动推导
	auto pi8 = make_shared<string>(5, 'a');

	// shared_ptr 分配的也是局部变量,会在函数结束的时候就会释放.
#endif

#if 0
	// 1.shared_ptr 引用计数的增加和减少
	// 1.1 引用计数的增加
	// 每个shared_ptr都会记录有多少个
	auto p1 = make_shared<int>(100);// 目前只有一个p1;
	auto p2(p1);// 智能指针定义时的初始化,p2和p1指向了相同的对象,此对象目前有两个引用者

	myfunc(p2);
	myfunc1(p2);

	// 作为函数的返回值,没有临时的智能指针,来接它,引用计数就恢复了
	auto p3 = myfunc2(p2);// p3来接它,就会+1,没有接它就会消亡了

	// 引用计数减少
	// 指向新对象,计数减1
	p3 = make_shared<int>(20);
	p2 = make_shared<int>(100);
	p3 = make_shared<int>(200);//指向新对象时,
#endif
#if 0
	// shared_ptr指针常用操作
	// 1. use_cout();返回
	shared_ptr<int> myp(new int(100));
	int icout = myp.use_count();// 1
	cout << icout << endl;
	shared_ptr<int> myp2(myp);
	icout = myp2.use_count();
	cout << icout << endl;

	// 2.unique():是否该智能指针独占某个指向的对象,也就是若只有一个智能指针指向某个对象,则unique()返回true;
	shared_ptr<int> myp3(new int(100));
	cout << myp3.unique() << endl;
	shared_ptr<int> myp4(myp3);
	cout << myp3.unique() << endl;// 0
	shared_ptr<int> myp5;
	cout << myp5.unique() << endl;// 0

	// 3.reset()恢复,复位和重置的意思.
	// a.reset()不带参数时
	// 若pi是唯一指向该对象的指针,那么释放pi所指向的对象,并置位为空
	// 若pi不是该唯一指向该对象的指针,则不释放pi所指向的对象,但指向该对象的引用计数会减少1,并将pi置空.

	shared_ptr<int> pi1(new int(100));
	pi1.reset();
	if (pi1 == nullptr)
	{
		string str = "_pi1 被置为空.";

		cout << str.c_str() << endl;
	}
	pi1 = make_shared<int>(100);
	shared_ptr<int> pi2(pi1);
	pi2.reset();
	if (pi2 == nullptr)
	{
		string str = "_pi2 被置为空.";
		cout << str.c_str() << pi1.use_count() <<endl;
	}


	// reset()带参数,一般是new出来的指针时
	// 若pi是唯一指向该对象的指针,则释放pi指向的对象,让pi指向新对象.
	// 若pi不是唯一指向该对象的指针,则不释放pi指向的对象,但指向该对象的引用计数减少1,同时让pi指向新对象
	shared_ptr<int> pi3(new int(100));
	pi3.reset(new int(120));
	auto pi4(pi3);
	pi3.reset(new int(1));

	// 空指针也可以通过reset来重新初始化
	shared_ptr<int> p;
	p.reset(new int(1));

	// *解引用,获取p指向的对象
	shared_ptr<int> pother(new int(123456));
	cout << *pother << endl;// 打印出123456

	// p.get(),返回p中保存的指针(裸指针),小心使用,如果智能指针释放了所指向的对象,那么这个返回的裸指针也就变得无效了
	// 考虑到有些函数的参数,需要的是一个内置裸指针而不是智能指针.
	shared_ptr<int> pi5(new int(100));
	int *p1 = pi5.get();
	*p1 = 34;
	cout << *pi5 << endl;// 打印出123456
	// delete p;.. 不要这样干,不然系统要报错,产生不可预料的结果.

	// swap();交换两个智能指针所指向的对象.
	shared_ptr<string> pi6(new string("qwe"));
	shared_ptr<string> pi7(new string("poi"));
	std::swap(pi6,pi7);

	int a = 10;
	int b = 20;
	std::swap(a, b);
	cout << a << " " << b << endl;

	// = nullptr 
	// 将所指向的对象,引用计数减1,若引用计数变为0,则释放智能指针所指向的对象.
	// 将智能指针置空
	shared_ptr<string> ps1(new string("Iloveyou"));
	shared_ptr<string> ps2(ps1);
	ps1 = nullptr;

	// 智能指针名字作为判断条件
	if (ps1)
	{
		cout << "指向一个对象." << endl;
	}
	else
	{
		cout << "指向空的对象." << endl;

	}

	// 指定删除器和数组问题
	// a.指定删除器
	// 一定时机帮我们删除所指向的对象,delete,将delete运算符号作为默认的资源析构方式.
	// 我们可以指定自己的删除器,来取代系统提供的默认删除器.当智能指针需要删除所指向的对象时,编译器就会调用我们自己的删除器.
	// shared_ptr 
	//void myDelete(int *p)// 我们的删除器,当整形指针用的,当引用计数为0,就会调用
	//{
	// delete p;
	// 
	//}
	shared_ptr<int> pi8(new int(123456),myDelete);
	shared_ptr<int> pi9(pi8);
	pi9.reset();// 剩一个引用计数
	pi8.reset();// 要释放指向对象,会调用咱们的删除器,自己来删除

	// 删除器可以是一个lambda表达式
	shared_ptr<int> pi10(new int(123456), [](int *p) 
	{
		cout << "delete p" << endl;
		delete p;
	});
	pi10.reset();

	// 有些情况,默认删除器处理不了,需要我们提供自己的指定的删除器.
	shared_ptr<int> pi11(new int[10], [](int *p)
	{
		delete[]p;
	});

	//shared_ptr<B> pB(new B[10]);// 这里会有异常,因为delete pA所指向的裸指针,而不是delete [] pA
	shared_ptr<B> pB(new B[2], [](B *p)
	{
		delete[]p;
	});


	// 可以用default_delete来做删除器,是标准库里的模板类
	shared_ptr<B> pB1(new B[2], std::default_delete<B[]>());
	
	// 定义数字的时候,添加[],在14等标准中有. 
	shared_ptr<B[]> pB2(new B[10]);
	shared_ptr<int[]> pi12(new int[10]);
	pi12[0] = 12;
	cout << pi12[0] << endl;

	shared_ptr<int> pintArr = make_shared_array<int>(5);
	shared_ptr<B> pintArrB = make_shared_array<B>(5);

	// 指定两个shared_ptr都指定了不同的删除器,只要他们所指向的对象类型相同,那么两个shared_ptr也属于同一个类型

	auto lamada1 = [](int *p)
	{
		cout << "lamada1" << endl;
		delete p;
	};
	auto lamada2 = [](int *p)
	{
		cout << "lamada2" << endl;
		delete p;
	};
	shared_ptr<int> pi13(new int(100),lamada1);
	shared_ptr<int> pi14(new int(200), lamada2);
	pi14 = pi13;// pi14先释放,调用lamada2释放.p1指定的对象引用计数为2.
	// 整个main释放后,再释放pi13,pi14指定的对象.
	// make_shared是提倡生成shared_ptr的方法,但是make_shared这种方法,没有办法指定自己的删除器了.
#endif


#if 0
	// weak_ptr 概述
	// 用来辅助shared_ptr进行工作. weak弱,反义词是强
	// 强指的是shared_ptr,弱指的是weak_ptr;这个智能指针指向一个由shared_ptr管理的对象.但是weak_ptr不控制shared_ptr的对象的生命周期.
	// 换言之,将weak_ptr绑定到shared_Ptr上并不会改变shared_ptr的引用计数.weak_ptr的构造和析构不会增加或者减少所指向对象的引用计数.

	// 当shared_ptr需要释放所指定对象的时候照常释放,不管是否有weak_ptr指向该对象.
	// 能力弱,也叫弱共享,弱引用,共享其他的shared_ptr所指向的对象,控制不了所指向对象的生存期.
	// 这个弱引用,weak_ptr的作用,理解为监视shared_ptr的生命周期用的,是一种对shared_ptr的扩充.
	// weak_ptr不是一种独立的智能指针,不能用来操作所指向的资源,看起来是shared_ptr的助手,旁观者.
	// weak_ptr能够监视到它所指向的对象是否存在.

	// 1.weak_ptr的时候,一般是用一个shared_ptr来初始化.
	auto pi = make_shared<int>(100);
	weak_ptr<int> piw(pi);// piw弱共享pi,pi引用计数不改变,但是弱引用计数会改变,会从0变成1
	// 强引用计数才能决定对象的生存期,弱引用计数并对对象的生存期没有影响.

	weak_ptr<int> piw2;
	piw2 = piw;// 现在pi是一个强引用,两个弱引用.
	// lock()检查weak_ptr所指向的对象是否存在,如果存在,那就返回一个指向该对象的shared_ptr,(指向对象的强引用计数就会+1).如果不存在,则返回空的shared_ptr.

	pi.reset();// pi就是唯一指向该对象的强引用智能指针,就会释放.同时将pi置空
	// 同时下面的代码,就返回为null
	auto pi2 = piw.lock();// pi2就是一个shared_ptr
	if (pi2 != nullptr)
	{
		// 指向的对象存在
		*pi2 = 12;
	}
#endif
#if 0
	// weak_ptr常用操作
	// 1.use_cout():获取与该弱指针共享对象的其他shared_ptr的数量,或者说获取当前所观测资源的强引用计数.
	auto pi = make_shared<int>(100);
	auto pi2(pi); // 是一个shared_ptr
	weak_ptr<int> piw(pi);
	int isc = piw.use_count();
	cout << isc << endl;// 2个强引用

	// 2.expired();是否过期的意思,弱指针的use_count()为0,表示该弱指针所指向的对象已经不存在了,则返回true.
	// 换句话说,这个函数用来判断,所观测的资源是否被释放了.
#if 0
	pi.reset();
	pi2.reset();
	if (piw.expired())
	{
		// 已经过期
		cout << "过期." << endl;// 2个强引用
	}
#endif
	// piw.reset();// 将弱引用指针设置为空,不影响该指向该对象的强引用数量,但指向该对象的弱引用数量会减少1.
#endif
#if 0
	// 2.4 lock()
	auto p1 = make_shared<int>(42);
	weak_ptr<int> pw;
	pw = p1; // 可以用强引用给弱引用赋值
	if (!pw.expired())// 没有过期
	{
		auto p2 = pw.lock();// 返回一个shared_ptr,并且强引用计数为2.
		if (p2 !=nullptr)
		{
			// 做一些操作
			int test;
			test = 1;
			// 离开这个作用域,强引用计数会恢复为1
		}
	}
	else
	{
		// 已经过期
	}
	// 走到这里,强引用计数变回为1.
#endif
#if 0
	// 尺寸问题
	// weak_ptr<int> pw
	// weak_ptr的尺寸和shared_ptr尺寸一样大,是裸指针的2倍
	weak_ptr<int> pw;
	int *p;
	int ilen1 = sizeof(p);
	int ilen2 = sizeof(pw);
	cout << ilen1 << " " << ilen2 << endl;// 4 ,8
	// shared_ptr<T> 和 weak_ptr<T> 有两个指针,1个指向T类型的对象.1个指向控制块的指针. 
	// 控制块: 包括应用计数,弱引用计数,其他数据如删除器等等.很大的数据结构

	// 本门是基本具备能够看懂读懂实战代码的能力,缺乏实战.
#endif
#if 0
	// std::shared_ptr使用场景
	//myfuncA(12);
	//myfuncB(12);// 如果这里不用shared_ptr变量来接收myfunc返回的结果,那么从myfunc返回的shared就会被销毁.
	auto pl1 = myfuncB(12);// 我们用一个变量来接myfunc返回值,那么返回的shared就不会被销毁.
#endif

#if 0
	// std::shared_ptr使用陷阱分析,一旦用错,也是致命的.
	// 2.1慎用裸指针.
	int *p = new int(100);// 裸指针
	// proc(p);// 语法错,int *p不能转成shared_ptr'
	//proc(shared_ptr<int>(p));// 这种不报错,参数是临时的shared_ptr.用一个裸指针显式的构造.
	//*p = 45;// 潜在不可预料的问题,因为p指向的内存已经被释放了.
	shared_ptr<int> p2(p);
	proc(p2);
	//*p = 10;// 把一个普通普通甪直镇绑定到了一个shared_ptr上,那么内存管理的责任就交给这个shared_ptr上了,这个时候就不应该再用裸指针(内置指针)来访问shared_ptr指向的内存了.
	*p2 = 10;// ok
	// 把裸指针定义直接提到智能指针定义上面来.
#endif
#if 0
	// 绝对要记住:不要用裸指针初始化多个shared_ptr;
	int *p = new int(100);// 裸指针
	shared_ptr<int> p1(p);
	shared_ptr<int> p2(p);// p1,p2关联两个.导致内存释放

	// 慎用get()返回的指针.
	// 返回的指针不能delete,否则会异常.
	int *pi1 = p1.get();
	//delete pi1;// 不可以删除,会导致异常
	{
		shared_ptr<int> p3(pi1);// 不能讲其他智能指针绑定到get返回的指针上了.
	}

	// 2.3 不要把类对象指针this作为shared_ptr返回,改用enable_shared_from_this
	shared_ptr<CT> pct1(new CT);
	 //shared_ptr<CT> pct2(pct1);// 这是两个强引用
	// shared_ptr<CT> pct3 = pct1->getSelf();// 问题出现,都返回一个强引用,会导致异常
	// 需要用到c++标准库里面的一个类模板解决此问题shared_ptr<CT> pct3 = pct1->getSelf();
	// enable_shared_from_this.
	shared_ptr<CT1> pct4(new CT1);
	shared_ptr<CT1> pct5 = pct4->getSelf();
	// 现在在外面创建ct1对象的智能指针都是安全的.
	// 这个enable_shared_from_this有一个弱指针weak_ptr,会监视this.
	// 调用shared_from_this()方法时,内部实际上是调用了weak_ptr的lock(),这个会让shared_ptr计数+1
#endif
#if 0
	// 循环引用
	shared_ptr<CA> pca(new CA);
	shared_ptr<CB> pcb(new CB);
	pca->m_pbs = pcb;// 等价于指向cb对象有两个强引用
	pcb->m_pas = pca;// 等价于指向ca对象有两个强引用
	// 两个析构都没有执行
#endif
#if 0
// 循环引用
	shared_ptr<CA> pca(new CA);
	shared_ptr<CC> pcc(new CC);// 一个弱引用
	pca->m_pcs = pcc;// 等价于指向cb对象有两个强引用
	pcc->m_pas = pca;// 因为指向CA的对象只有一个强引用了.
	// 离开作用域了,就会释放CA对象.CA析构函数被指向,这一释放,导致这个CA内的引用计数减1,导致pcb的作用域,指向cc的计数会减1,从1减为0,从而释放.
	// 交叉使用.一个使用强引用,一个使用弱引用.
#endif
#if 0
	// 性能说明
	// 是裸指针的两倍.
	// a. 第一个裸指针指向的是整个智能指针所指向的对象
	// b.第二个裸指针指向一个很大的数据结构(控制块),这个控制块里边有啥.
	// b.1所指对象的强引用计数shared_ptr
	// b.2 所指对象的弱引用计数,weak_ptr
	// b.3 其他数据,比如删除器指针,内存分配器.
	// 这个控制块是由第一个指向某个对象的shared_ptr来创建的.
	// 控制块创建时机:make_shared:分配并初始化一个对象,返回指向此对象的shared_ptr

	// 移动语义
	shared_ptr<int> p1(new int(100));
	shared_ptr<int> p2(std::move(p1));// 电影语义,移动构造一个新的智能指针对象p2
	// p1 就不再指向该对象,引用计数依旧是1;
	shared_ptr<int> p3;
	p3 = std::move(p2);// 移动赋值,p2指向空,p3指向该对象,整个对象引用计数依旧为1.

	// 使用建议
	// 分配器解决了内存分配
	// shared_ptr<int> p(new(),mydelete());
	shared_ptr<string> ps1(new string("I love you"));// 分配两次内存
	auto ps2 = make_shared<string>("I love you ");// 分配一次内存

#endif

#if 0
	// unique_ptr
	// 独占式的概念:专属于所有权,同一时刻
	// 格式
	// unique_ptr<指向的对象类型> 变量名;//
	// 1.常规初始化,unique_ptr和new配合
	unique_ptr<int> pi;// 可以指向int对象的一个空智能指针
	if (pi == nullptr)
	{
		cout << "pi为空." << endl;
	}
	unique_ptr<int> pi2(new int(105));// 此时pi指向一个值为105的int对象.

	// 1.2 make_unique函数.在c++14才有
	//,不支持指定的删除器语法.如果不用删除器,有限选择使用,更高的性能
	unique_ptr<int> p1 = make_unique<int>(100);
	auto p2 = make_unique<int>(200);

	// 常用操作,独占式,不支持多个指向同一个
	unique_ptr<string> ps1(new string("i lvoe you"));
	// unique_ptr<string> ps2(ps1);// 不支持拷贝动作,复制
	// unique_ptr<string> ps3 = ps1;
	// unique_ptr<string> ps4;
	// ps4 = ps3;// err

	// 移动语义
	unique_ptr<string> ps10(new string("ilove you "));
	unique_ptr<string> ps11 = std::move(ps10);

#endif
#if 0
	// release() 放弃对指针的控制权,切换了智能指针与其指向的对象之间的联系
	// 返回裸指针,并将该智能指针置空,返回的这个裸指针,我们可以手工delete来释放,也可以用来初始化另外一个智能指针.
	unique_ptr<string> ps1(new string("i lvoe you"));
	unique_ptr<string> ps2(ps1.release());
	// ps2.release();// 此处导致内存泄漏
	// 可以这样写
	string *temp = ps2.release();
	delete temp;// 人工释放
#endif

#if 0
	// reset()
	// 不带参数的情况:释放智能指针所指向的对象,并该该智能指针置空.
	unique_ptr<string> ps1(new string("i love china"));
	//ps1.reset();// 没有内存泄漏

	// reset() 带参数的情况,释放智能指针所指向的对象,并让该智能指针指向该对象
	unique_ptr<string> ps2(new string("i love china"));
	ps1.reset(ps2.release());// 意思是先释放ps1指向的内存,再指向ps2所指向的内存
	ps1.reset(new string("i love china3"));
	
	// 指针= nullptr;释放智能指针指向的对象,并将该智能指针置空
	unique_ptr<string> ps3(new string("i love china!"));
	ps3 = nullptr;// 释放ps3所指向的对象,并将ps3置空

	// 指向一个数组
	unique_ptr<int[]> ptrarry(new int[10]);
	ptrarry[0] = 12;
	// 不要忘记unique_ptr<int[]> [],否则有自己的析构函数,则会报异常.


	// get();返回智能指针中保存的裸指针.因为有些函数必须使用裸指针,第三方库,改不了代码
	unique_ptr<string> ps4(new string("i love you"));
	string *ps = ps4.get();
	*ps = "aaa";
	// delete ps;// 不要这么干,否则产生不可预料的后果.

	// *解引用,获取该智能指针指向的对象,可以直接操作.
	unique_ptr<string> ps5(new string("i love you"));
	*ps5 = "ssss";
	unique_ptr<int> ps6(new int(100));
	*ps6 = 200;
	
	unique_ptr<int[]> pi8(new int[10]);
	// 没有*解引用的.
	pi8[0] = 10;
	// *(pi8 + 1) = 11;

	// swap() :交换两个智能指针所指向的对象
	std::swap(ps1, ps2);
	ps1.swap(ps2);

#endif
#if 0
	// 转换成shared_ptr类型,如果unique_ptr为右值,就可以将它赋值给shared_ptr
	// shared_ptr包含成一个显示构造函数,可用于把右值unique_ptr转换为shared_ptr,将接管原来的unique_ptr
	//shared_ptr<string> pss1 = myfuncC();// 创建控制块
	unique_ptr<string> ps1(new string("i love you"));
	shared_ptr<string> ps2 = std::move(ps1);// 左值作为右值,执行完ps1为空,ps2就是
#endif
#if 0
	// 1.返回unique_ptr
	// 最常用的就是函数返回一个对象
	unique_ptr<string> ps;

	ps = tuniqep();// 可以用ps来接,则临时对象直接构造在ps里,如果不接,则近视对象会被释放.同时会释放掉所指向的对象
	// 指定删除器,就是delete默认删除器
	// 格式:unique_ptr<指定对象类型,删除器> 智能指针变量名
	// 删除器,可调用对象,比如函数,重载了()
	// 我们学习了,shared_ptr山湖传奇,比较简单.shared_ptr<int> p(new(),myfunc);
	// unique_ptr删除器相对复杂一点,多了一部,先要在类型模板参数中传递进去类型名,在参数中再给具体的删除器函数
	// 第一种写法
	typedef void(*fp)(string*);// 定义了一个函数指针类型为fp
	unique_ptr<string, fp> ps1(new string("aaa"),mydeleteer);
	// 第二种
	using fp2 = void(*)(string *);
	unique_ptr<string, fp2>ps2(new string("aa"), mydeleteer);

	// 第三种
	typedef decltype(mydeleteer) *fp3;// 多个* 
	// decltype返回的是函数类型 .表示是函数指针类型
	unique_ptr<string, fp3>ps4(new string("aa"), mydeleteer);

	// 第四种
	unique_ptr<string, decltype(mydeleteer)*> ps5(new string("aaa"), mydeleteer);

	// lambda表达式写法
	auto mylambda = [](string *pdel) 
	{
		delete pdel;
		pdel = nullptr;
	};

	unique_ptr<string, decltype(mylambda)> ps6(new string("aaa"), mylambda);
#endif
#if 1
	// unique_ptr<string, decltype(mylambda)>是整个类型,相同类型的可以放到同一个容器里面.
	// shared_ptr更灵活.

	// 尺寸问题,通常情况下,unique_ptr和裸指针一样
	string *p;
	unique_ptr<string> ps1(new string("i love"));
	int ilen = sizeof(ps1);
	// 如果增添了删除器,可能增加,也可能不增加
	// a.如果是lambda是不增加的.
	// 函数指针类型是增加的.
	
	// 总结:
	// 主要目的,帮助我们释放内存,以防止我们忘记释放内存时造成的内存泄漏
	//c++98 auto_ptr 理解为unique_ptr
	// auto_ptr : 不能够在容器中保存,也不能从函数中返回auto_ptr;
	auto_ptr<string> ps(new string("iloveyou"));
	auto_ptr<string> ps2 = ps;// 如果ps为空了ps2就会 崩溃
	// 用unique_ptr取代了auto_ptr
	// a.多个指向同一个对象的指针,选择shared_ptr
	// b.不需要多个指向同一个对象的指针,选择unique_ptr

#endif


	cout << "Hello World!" << endl;
	return 0;
}
